package com.jf.anmocker.plugin.mockcore.asm

import com.jf.mocker.anotations.IClassMocker
import groovyjarjarasm.asm.Opcodes
import org.objectweb.asm.AnnotationVisitor
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Type

class AnMockerClzVisitor(val api : Int = Opcodes.ASM6,val nextVisitor : ClassVisitor) : ClassVisitor(api, nextVisitor) {

    override fun visit(
        version: Int,
        access: Int,
        name: String?,
        signature: String?,
        superName: String?,
        interfaces: Array<out String>?
    ) {
        //保存引用
        saveClassToPool(name)
        super.visit(version, access, name, signature, superName, interfaces)
    }

    override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor {
        //println("visitAnnotation descriptor = $descriptor")
        return if(Type.getDescriptor(IClassMocker::class.java).equals(descriptor)){
            //IClassMocker annotation 注释数据解析
            val clzAnoVisitor = AnMockerAnoVisitor(super.visitAnnotation(descriptor, visible))
            markTargetClzByAno(clzAnoVisitor)
            return clzAnoVisitor
        }else{
            super.visitAnnotation(descriptor, visible)
        }
    }

    override fun visitMethod(
        access: Int,
        name: String?,
        descriptor: String?,
        signature: String?,
        exceptions: Array<out String>?
    ): MethodVisitor {
        //println("visitMethod >>> $name")
        val methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions)
        return AnMockerMethodVisitor(api, methodVisitor, access, name, descriptor)
        //return super.visitMethod(access, name, descriptor, signature, exceptions)
    }

    private fun saveClassToPool(name: String?){
        if(name != null && name.isNotEmpty()){
            AsmMockerCache.getInstance().saveClassVisitor(name, this)
        }
    }

    private fun markTargetClzByAno(clzMockerAnoVisitor: AnMockerAnoVisitor){
        //标记目标类
        if(clzMockerAnoVisitor.getAnoValue() is String){
            AsmMockerCache.getInstance()
                .markTargetClass(clzMockerAnoVisitor.getAnoValue() as String, this)
        }
    }
}